## Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php

## Needed to handle armory characters.
import wowarmorycharacter

## Needed to check the URLs to see if they are what we are expecting
import re

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app


def fetch_character(page_self, handle, base_character_url, callback_id):
	## Lists of achievements and stats pages generated via:
	## $ for file in achievement/*; do echo "\"$file\"," ; done
	## In a directory where the pages for a character have been downloaded.
	page_types = [
		"advanced",
		"statistic/21",
		"statistic/122",
		"statistic/128",
		"statistic/130",
		"statistic/131",
		"statistic/132",
		"statistic/133",
		"statistic/134",
		"statistic/141",
		"statistic/14807",
		"achievement/97",
		"achievement/96",
		"achievement/95",
		"achievement/92",
		"achievement/81",
		"achievement/201",
		"achievement/187",
		"achievement/172",
		"achievement/171",
		"achievement/170",
		"achievement/169",
		"achievement/168",
		"achievement/165",
		"achievement/163",
		"achievement/162",
		"achievement/161",
		"achievement/160",
		"achievement/159",
		"achievement/158",
		"achievement/156",
		"achievement/155",
		"achievement/15092",
		"achievement/15081",
		"achievement/15075",
		"achievement/15074",
		"achievement/15073",
		"achievement/15072",
		"achievement/15071",
		"achievement/15070",
		"achievement/15069",
		"achievement/15068",
		"achievement/15067",
		"achievement/15003",
		"achievement/14981",
		"achievement/14941",
		"achievement/14922",
		"achievement/14901",
		"achievement/14881",
		"achievement/14866",
		"achievement/14865",
		"achievement/14864",
		"achievement/14863",
		"achievement/14862",
		"achievement/14861",
		"achievement/14808",
		"achievement/14806",
		"achievement/14805",
		"achievement/14804",
		"achievement/14803",
		"achievement/14802",
		"achievement/14801",
		"achievement/14780",
		"achievement/14779",
		"achievement/14778",
		"achievement/14777"
	]

	## If we have a callback id, give it out and print the id and ( before the {
	if callback_id:
		handle.write("%s({\n" % (callback_id))
	else:
		## Just print the normal start of a JSON document: {
		handle.write("{\n")


	## Only fetch the page if the page_type is known to us.
	page_type = page_self.request.get("page_type")

	if (page_type in page_types):
		page = wowarmorycharacter.ArmoryCharacterPage(base_character_url, page_type)

		## If we were able to retrieve the page, print out the data element from it.
		if not (page.get()):
			## Print this first as it clear the output buffer.
			page_self.error(500)

			## Different output rules for jsonp vs. json
			if callback_id:
				handle.write("%s({\n" % (callback_id))
			else:
				## Just print the normal end of a JSON document: {
				handle.write("{\n")

			handle.write("  \"status\":\"nok\",\n  \"reason\":\"Attempt to fetch %s has failed.\"" % (page.url))

			## If we are printing a JSONP document we have to close the () and add a ;
			if callback_id:
				handle.write("\n});\n")
			else:
				## Just print the normal end of a JSON document: {
				handle.write("\n}\n")
			return
		else:
			## If we are printing achievements print out the appropriate headers
			if (page_type.find('achievement/') > -1):
				first_data = True
				## For every achievement ID, print out the various kinds of data
				for achievement_id in (page.page_data["achievements"]).keys():
					if first_data:
						## If this is the first data element don't print out a "," at the start as we're the first
						## if it is not the first data element then we've printed something above, so we need to
						## finish it off with a "," and a newline. JSON validation is sensitive to this.
						## http://www.jsonlint.com/
						first_data = False
					else:
						handle.write(",\n")

					handle.write("  \"%s\" : {\n" %  (achievement_id))
					first_data_name = True
					for achievement_data_name in sorted((page.page_data["achievements"][achievement_id]).keys()):
						if first_data_name:
							handle.write("    \"%s\" : \"%s\"" %  (achievement_data_name, (page.page_data["achievements"][achievement_id][achievement_data_name]).replace('"', '\\"')))
							first_data_name = False
						else:
							handle.write(",\n    \"%s\" : \"%s\"" %  (achievement_data_name, (page.page_data["achievements"][achievement_id][achievement_data_name]).replace('"', '\\"')))
					handle.write("\n  }")
			else:
				## No errors, so go ahead and print out any data we have.
				first_data = True
				for data_name in sorted((page.page_data).keys()):
					## If this is the first data element don't print out a "," at the start as we're the first
					## if it is not the first data element then we've printed something above, so we need to
					## finish it off with a "," and a newline. JSON validation is sensitive to this.
					## http://www.jsonlint.com/
					if first_data:
						handle.write("  \"%s\":\"%s\""    % (data_name, page.page_data[data_name]))
						first_data = False
					else:
						handle.write(",\n  \"%s\":\"%s\"" % (data_name, page.page_data[data_name]))

	else:
		## The page type was not known to us, so throw a 500 error and be
		## informative.
		## Print this first as it clear the output buffer.
		page_self.error(500)

		## Different output rules for jsonp vs. json
		if callback_id:
			handle.write("%s({\n" % (callback_id))
		else:
			## Just print the normal end of a JSON document: {
			handle.write("{\n")

                ## Take the query strings off of the URL, as we are going to use it
                ## as a starting point for some advice to the user.
                requested_url_path = (page_self.request.url).replace(page_self.request.query_string, "")
                ## Strip off the remaining "?" as well
                requested_url_path = requested_url_path.replace("?", "")

		handle.write("  \"status\":\"nok\",\n")
		handle.write("  \"reason\":\"We don't know how to fetch pages of type '%s'.\",\n" % (page_type))
		handle.write("  \"try this\":\"%s?page_type=advanced\",\n" % (requested_url_path))
		handle.write("  \"or try this\":\"%s?page_type=statistic/131\",\n" % (requested_url_path))
		handle.write("  \"info\":\"Supported page types: '%s'.\",\n" % (page_types))

		## If we are printing a JSONP document we have to close the () and add a ;
		if callback_id:
			handle.write("\n});\n")
		else:
			## Just print the normal end of a JSON document: {
			handle.write("\n}\n")
		return

	## If we are printing a JSONP document we have to close the () and add a ;
	if callback_id:
		handle.write("\n});\n")
	else:
		## Just print the normal end of a JSON document: {
		handle.write("\n}\n")


class MainPage(webapp.RequestHandler):
	def get(self):
		errors = False
		path = self.request.path

		## Does the URL that were were accessed via make sense? Is it of the pattern that
		## we are expecting? If it isn't throw an informative error.
		api_url = re.compile('/api/wow/character/.*/.*')
		if not api_url.match(path):
			self.response.headers['Content-Type'] = 'text/plain'
			self.response.out.write("I don't understand this path!: ")
			self.response.out.write(path)
			self.response.out.write('''
I'm expecting a path that looks like this:
/api/wow/character/REALM_NAME/CHARACTER_NAME?page_type=PAGE_TYPE
/api/wow/character/tichondrius/deathnerd?page_type=statistic/131
''')
			return

		## If there are no errors, we're good to go so go ahead and fetch the page
		if not errors:
			## Determine if we are jsonp or json (default) as that determines if we set the
			## Access-Control-Allow-Origin header and what we set the Content-Type header to.
			if self.request.get("jsonp"):
				## Make a note of the value of our jsonp parameter so we can wrap
				## the json data in a function by that name
				callback_id=self.request.get("jsonp")
				## We are going to be returning text, so set the content type to
				## match the javascript that we will be sending back
				self.response.headers['Content-Type'] = 'application/javascript'
			else:
				## We are not jsonp, so default to json settings, including setting the
				## callback to nothing, so we don't wrap the json output.	
				callback_id=""
				## We are going to be returning json, so set the content type accordingly
				self.response.headers['Content-Type'] = 'application/json'
				## We want people to be able to fetch this json data so set a liberal
				## Access-Control-Allow-Origin header otherwise folks won't be able to
				## include this data in their own pages.
				self.response.headers['Access-Control-Allow-Origin'] = '*'

			server = "us.battle.net"
			if self.request.get("region"):
				region = self.request.get("region")
				if region == "eu":
					server = "eu.battle.net"
				if region == "kr":
					server = "kr.battle.net"
				if region == "tw":
					server = "tw.battle.net"


			## Parse this armory URL and pull out the realm and character name
			## so we can construct the URL that we will have to fetch from the armory
			path_array = path.split('/')
			realm = path_array[4]
			character = path_array[5]

			armory_url = "http://%s/wow/en/character/%s/%s/" % (server, realm, character)
			fetch_character(self, self.response.out, armory_url, callback_id)


application = webapp.WSGIApplication([('/.*', MainPage), ], debug=True)

def main():
	run_wsgi_app(application)

if __name__ == '__main__':
	main()



